export class Visualizer {
    constructor(canvas) {
        this.canvas = canvas;
        this.ctx = canvas.getContext('2d');
        this.array = [];
        this.arrayStates = [];
        this.width = canvas.width;
        this.height = canvas.height;
        this.padding = 20;
        this.barWidth = 0;
        this.barSpacing = 2;
        this.maxValue = 100;
        this.animationFrameId = null;
        
        this.colors = {
            default: '#667eea',
            comparing: '#ff6b6b',
            swapping: '#4ecdc4',
            sorted: '#45b7d1',
            pivot: '#feca57'
        };
    }

    generateArray(size) {
        this.array = [];
        for (let i = 0; i < size; i++) {
            this.array.push(Math.floor(Math.random() * this.maxValue) + 1);
        }
        this.arrayStates = [...this.array];
        this.calculateDimensions();
        this.scheduleDraw();
    }

    calculateDimensions() {
        const availableWidth = this.width - 2 * this.padding;
        this.barWidth = (availableWidth - (this.array.length - 1) * this.barSpacing) / this.array.length;
    }

    draw() {
        this.ctx.clearRect(0, 0, this.width, this.height);
        
        const barHeight = this.height - 2 * this.padding;
        const maxBarHeight = barHeight * 0.8;
        
        for (let i = 0; i < this.array.length; i++) {
            const x = this.padding + i * (this.barWidth + this.barSpacing);
            const barValue = this.array[i];
            const height = (barValue / this.maxValue) * maxBarHeight;
            const y = this.height - this.padding - height;
            
            this.ctx.fillStyle = this.getBarColor(i);
            this.ctx.fillRect(x, y, this.barWidth, height);
            
            this.ctx.fillStyle = '#333';
            this.ctx.font = '12px Arial';
            this.ctx.textAlign = 'center';
            this.ctx.fillText(barValue.toString(), x + this.barWidth / 2, y - 5);
        }
    }

    scheduleDraw() {
        if (this.animationFrameId) {
            cancelAnimationFrame(this.animationFrameId);
        }
        this.animationFrameId = requestAnimationFrame(() => this.draw());
    }

    getBarColor(index) {
        if (this.highlightedIndices) {
            if (this.highlightedIndices.includes(index)) {
                return this.colors[this.highlightType] || this.colors.comparing;
            }
        }
        return this.colors.default;
    }

    highlight(indices, type = 'comparing') {
        this.highlightedIndices = indices;
        this.highlightType = type;
        this.scheduleDraw();
    }

    clearHighlight() {
        this.highlightedIndices = null;
        this.highlightType = null;
        this.scheduleDraw();
    }

    async swap(i, j) {
        const temp = this.array[i];
        this.array[i] = this.array[j];
        this.array[j] = temp;
        
        this.scheduleDraw();
        await this.delay(100);
    }

    async compare(i, j, val1 = null, val2 = null) {
        this.highlight([i, j], 'comparing');
        await this.delay(100);
        
        const a = val1 !== null ? val1 : this.array[i];
        const b = val2 !== null ? val2 : this.array[j];
        return a > b;
    }

    async set(index, value) {
        this.array[index] = value;
        this.highlight([index], 'sorted');
        await this.delay(100);
    }

    async delay(ms) {
        return new Promise(resolve => {
            const start = performance.now();
            const checkTime = (timestamp) => {
                if (timestamp - start >= ms) {
                    resolve();
                } else {
                    requestAnimationFrame(checkTime);
                }
            };
            requestAnimationFrame(checkTime);
        });
    }

    markSorted() {
        this.highlight(Array.from({length: this.array.length}, (_, i) => i), 'sorted');
    }

    reset() {
        this.array = [...this.arrayStates];
        this.clearHighlight();
    }

    destroy() {
        if (this.animationFrameId) {
            cancelAnimationFrame(this.animationFrameId);
        }
    }
}